import 'dart:convert';

import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_app_update/azhon_app_update.dart';
import 'package:flutter_app_update/update_model.dart';
import 'package:flutter_app_update/result_model.dart';

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  group('Az honAppUpdate Tests', () {
    const MethodChannel channel = MethodChannel('azhon_app_update');
    const EventChannel eventChannel = EventChannel('azhon_app_update_listener');

    late List<MethodCall> log;

    setUp(() {
      log = <MethodCall>[];
      TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
          .setMockMethodCallHandler(channel, (MethodCall methodCall) async {
        log.add(methodCall);
        switch (methodCall.method) {
          case 'getVersionCode':
            return 1;
          case 'getVersionName':
            return '1.0.0';
          case 'update':
            return true;
          case 'install':
            return true;
          case 'cancel':
            return true;
          default:
            return null;
        }
      });
    });

    tearDown(() {
      TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
          .setMockMethodCallHandler(channel, null);
      AzhonAppUpdate.dispose();
    });

    test('getVersionCode returns correct value', () async {
      final int versionCode = await AzhonAppUpdate.getVersionCode;
      expect(versionCode, 1);
      expect(log, <Matcher>[isMethodCall('getVersionCode', arguments: null)]);
    });

    test('getVersionName returns correct value', () async {
      final String versionName = await AzhonAppUpdate.getVersionName;
      expect(versionName, '1.0.0');
      expect(log, <Matcher>[isMethodCall('getVersionName', arguments: null)]);
    });

    test('update method calls channel with correct parameters', () async {
      final UpdateModel model = UpdateModel(
        'https://example.com/app.apk',
        'app.apk',
        'ic_launcher',
        'https://itunes.apple.com/app/id123456789',
        apkMD5: 'md5hash',
        showNotification: true,
        jumpInstallPage: true,
        showBgdToast: true,
      );

      final bool result = await AzhonAppUpdate.update(model);
      
      expect(result, true);
      expect(log.length, 1);
      expect(log[0].method, 'update');
      expect(log[0].arguments, <String, dynamic>{
        'model': <String, dynamic>{
          'apkUrl': 'https://example.com/app.apk',
          'apkName': 'app.apk',
          'smallIcon': 'ic_launcher',
          'iOSUrl': 'https://itunes.apple.com/app/id123456789',
          'apkMD5': 'md5hash',
          'showNotification': true,
          'jumpInstallPage': true,
          'showBgdToast': true,
        }
      });
    });

    test('install method calls channel with correct parameters', () async {
      final String apkPath = '/storage/emulated/0/Download/app.apk';
      final String? authorities = 'com.example.fileprovider';
      
      final bool result = await AzhonAppUpdate.install(apkPath, authorities: authorities);
      
      expect(result, true);
      expect(log.length, 1);
      expect(log[0].method, 'install');
      expect(log[0].arguments, <String, dynamic>{
        'authorities': authorities,
        'path': apkPath,
      });
    });

    test('install method works without authorities', () async {
      final String apkPath = '/storage/emulated/0/Download/app.apk';
      
      final bool result = await AzhonAppUpdate.install(apkPath);
      
      expect(result, true);
      expect(log.length, 1);
      expect(log[0].method, 'install');
      expect(log[0].arguments, <String, dynamic>{
        'authorities': null,
        'path': apkPath,
      });
    });

    test('cancel method calls channel correctly', () async {
      final bool result = await AzhonAppUpdate.cancel;
      
      expect(result, true);
      expect(log, <Matcher>[isMethodCall('cancel', arguments: null)]);
    });

    test('ResultModel.fromJson parses correctly', () {
      final Map<String, dynamic> json = {
        'type': 'downloading',
        'max': 100,
        'progress': 50,
        'apk': '/path/to/app.apk',
        'exception': null,
      };

      final ResultModel model = ResultModel.fromJson(json);
      
      expect(model.type, ResultType.downloading);
      expect(model.max, 100);
      expect(model.progress, 50);
      expect(model.apk, '/path/to/app.apk');
      expect(model.exception, null);
    });

    test('ResultType.from converts string correctly', () {
      expect(ResultType.from('start'), ResultType.start);
      expect(ResultType.from('downloading'), ResultType.downloading);
      expect(ResultType.from('done'), ResultType.done);
      expect(ResultType.from('cancel'), ResultType.cancel);
      expect(ResultType.from('error'), ResultType.error);
    });

    test('UpdateModel.toJson generates correct JSON', () {
      final UpdateModel model = UpdateModel(
        'https://example.com/app.apk',
        'app.apk',
        'ic_launcher',
        'https://itunes.apple.com/app/id123456789',
        apkMD5: 'md5hash',
        showNotification: false,
        jumpInstallPage: false,
        showBgdToast: false,
      );

      final Map<String, dynamic> json = model.toJson();
      
      expect(json['apkUrl'], 'https://example.com/app.apk');
      expect(json['apkName'], 'app.apk');
      expect(json['smallIcon'], 'ic_launcher');
      expect(json['iOSUrl'], 'https://itunes.apple.com/app/id123456789');
      expect(json['apkMD5'], 'md5hash');
      expect(json['showNotification'], false);
      expect(json['jumpInstallPage'], false);
      expect(json['showBgdToast'], false);
    });

    test('UpdateModel.toJson handles null apkMD5', () {
      final UpdateModel model = UpdateModel(
        'https://example.com/app.apk',
        'app.apk',
        'ic_launcher',
        'https://itunes.apple.com/app/id123456789',
      );

      final Map<String, dynamic> json = model.toJson();
      
      expect(json['apkMD5'], '');
    });
  });

  group('Event Listener Tests', () {
    const EventChannel eventChannel = EventChannel('azhon_app_update_listener');

    setUp(() {
      // 确保每次测试前都清理监听器
      AzhonAppUpdate.dispose();
    });

    tearDown(() {
      // 清理监听器
      AzhonAppUpdate.dispose();
    });

    test('listener can be registered and disposed', () async {
      bool callbackCalled = false;
      
      // 注册监听器
      AzhonAppUpdate.listener((ResultModel model) {
        callbackCalled = true;
      });
      
      // 验证监听器可以被释放
      AzhonAppUpdate.dispose();
      
      // 验证没有错误发生
      expect(true, true);
    });
  });
}